<?php

namespace App\Kuafu\Order\Service;

use App\Kuafu\Category\Service\CategoryService;
use App\Kuafu\Common\Service\SeparateService;
use App\Kuafu\Coupon\Enum\CouponEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Model\Clickhouse\OrderCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderDetailCHModel;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDiscountSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Product\Enum\CodeEnum as ProductCodeEnum;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\Clickhouse\WaiMaiOrderCHModel;
use App\Kuafu\WaiMai\Model\Clickhouse\WaiMaiOrderDetailCHModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderDetailModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use App\Support\Util;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

/**
 * 日结单服务
 */
class OrderStatisticsService
{
    private $shopId, $startTime, $endTime;

    public function setShopStartEndTime(int $shopId, $startTime, $endTime)
    {
        $this->shopId    = $shopId;
        $this->startTime = $startTime;
        $this->endTime   = $endTime;
    }


    /**
     * 剔除日结单现金数据中退款的数据
     *
     * @param Collection $payStream
     * @return int[]
     */
    public static function dailySettlementCashOutRefund(Collection $payStream): array
    {
        $orderId         = $payStream->pluck('orderId')->unique()->toArray();
        $refundStreamRes = RefundStreamModel::query()
                                            ->where('refundChannel', PayStreamModel::PAY_CHANNEL_CASH)
                                            ->whereIn('orderId', $orderId)
                                            ->select(['orderId', 'refundPrice'])
                                            ->get()
                                            ->groupBy('orderId');

        $afterHandlePayStream = $payStream->groupBy('orderId')->map(function (Collection $v, $orderId) use (
            $refundStreamRes
        ) {
            $item = [
                'orderId'     => $orderId,
                'refundPrice' => isset($refundStreamRes[$orderId]) ? $refundStreamRes[$orderId]->sum('refundPrice') : 0,
                'payPrice'    => $v->sum('payPrice'),
                'refundAll'   => false
            ];
            if ($item['refundPrice'] == $item['payPrice']) {
                $item['refundAll'] = true;
            }
            return (object)$item;
        })->values();


        return [
            'count' => (int)$afterHandlePayStream->where('refundAll', '=', false)->count(),
            'sum'   => (int)($afterHandlePayStream->sum('payPrice') - $afterHandlePayStream->sum('refundPrice')),
        ];
    }

    // 营业收款构成
    public function payStatisticsQuery($payChannel, $payChannelChild, $payAction = 0)
    {
        $payStreamRes = PayStreamModel::suffix($this->shopId, PayStreamModel::SYS_TYPE_RMS_MEAL)
                                      ->where('shopId', $this->shopId)
                                      ->where('sysType', PayStreamModel::SYS_TYPE_RMS_MEAL)
                                      ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                      ->where('payStatus', PayStreamModel::PAY_STATUS_1)
                                      ->when($payChannel, function ($item) use ($payChannel) {
                                          if (is_array($payChannel)) {
                                              $item->whereIn('payChannel', $payChannel);
                                          } else {
                                              switch ($payChannel) {
                                                  case PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT:
                                                      //关联自定义支付信息获取
                                                      $item->where('payChannel', '>=', $payChannel)
                                                           ->with([
                                                               'streamCustomPaymentRel' => function ($query) {
                                                                   $query->select(['id', 'name']);
                                                               }
                                                           ]);
                                                      break;
                                                  default:
                                                      $item->where('payChannel', $payChannel);
                                                      break;
                                              }

                                          }
                                      })
                                      ->when($payChannelChild, function ($item) use ($payChannelChild) {
                                          $item->where('payChannelChild', $payChannelChild);
                                      })
                                      ->when($payAction, function ($item) use ($payAction) {
                                          if (is_array($payAction)) {
                                              $item->whereIn('payAction', $payAction);
                                          } else {
                                              $item->where('payAction', $payAction);
                                          }
                                      })
                                      ->select(['isPaidIn', 'payPrice', 'orderId', 'payChannel'])->get();


        switch ($payChannel) {
            case PayStreamModel::PAY_CHANNEL_CASH:
                //现金渠道支付   剔除现金退款
                $res = $this->dailySettlementCashOutRefund($payStreamRes);
                break;
            case PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT:
                //自定义支付
                $res = [
                    //计入实收
                    'income'   => [
                        'count' => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                                                     ->groupBy('payChannel')->count(),
                        'sum'   => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_YES)->sum('payPrice'),
                        'lists' => $payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_YES)->groupBy('payChannel')
                                                ->map(function (Collection $v) {
                                                    return [
                                                        'count' => $v->count(),
                                                        'sum'   => $v->sum('payPrice'),
                                                        'name'  => $v->getIterator()
                                                                     ->current()->streamCustomPaymentRel->name
                                                    ];
                                                })->values()
                    ],
                    //计入优惠
                    'discount' => [
                        'name'  => '自定义支付(优惠)',
                        'count' => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_NO)
                                                     ->groupBy('payChannel')->count(),
                        'sum'   => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_NO)->sum('payPrice'),
                        'lists' => $payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_NO)->groupBy('payChannel')
                                                ->map(function (Collection $v) {
                                                    return [
                                                        'count' => $v->count(),
                                                        'sum'   => $v->sum('payPrice'),
                                                        'name'  => $v->getIterator()
                                                                     ->current()->streamCustomPaymentRel->name
                                                    ];
                                                })->values()
                    ]
                ];
                break;
            default:
                $res = [
                    'count' => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_YES)->groupBy('orderId')
                                                 ->count(),
                    'sum'   => (int)$payStreamRes->where('isPaidIn', PayStreamModel::PAID_IN_YES)->sum('payPrice'),
                ];
                break;
        }

        if (in_array($payChannelChild,
                [
                    PayStreamModel::PAY_CHANNEL_CHILD_WX,
                    PayStreamModel::PAY_CHANNEL_CHILD_ALI,
                    PayStreamModel::PAY_CHANNEL_CHILD_UNION_PAY,
                ]) && $payAction == 0) {

            // 主扫（主扫+小程序支付）
            $res['activeScan'] = $this->payStatisticsQuery($payChannel, $payChannelChild,
                [PayStreamModel::PAY_ACTION_SCAN, PayStreamModel::PAY_ACTION_MINI]);

            // 被扫
            $res['passiveScan'] = $this->payStatisticsQuery($payChannel, $payChannelChild,
                PayStreamModel::PAY_ACTION_QRCODE);
        }

        return $res;
    }

    // 敏感操作 - 打折、减免
    public function dangerDiscount(int $discountType, $shopId): array
    {

        $discountQuery = OrderDiscountSplitModel::suffix($shopId)
                                                ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                                ->when($discountType, function ($item) use ($discountType) {
                                                    $item->where('discountType', $discountType);
                                                });

        return [
            'count' => (int)$discountQuery->count(),
            'sum'   => (int)$discountQuery->sum('discountPrice'),
        ];
    }

    // 外卖
    public function waiMaiQuery(int $sourceType = 0): array
    {
        $orderQuery = WaiMaiOrderModel::suffix($this->shopId)
                                      ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                      ->where('shopId', $this->shopId)
                                      ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                                      ->when($sourceType, function ($query) use ($sourceType) {
                                          $query->where('sourceType', $sourceType);
                                      });

        return [
            'count'            => (int)$orderQuery->count(),
            'sum'              => (int)$orderQuery->sum('expectIncome'),
            'sumPlatformPrice' => (int)$orderQuery->sum('platformPrice'),
        ];
    }

    // 活动
    public function activityQuery(array $couponIds = [], $activityName = '店内活动'): array
    {
        $activityQuery = OrderCouponSplitModel::suffix($this->shopId)
                                              ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                              ->where('shopId', $this->shopId)
                                              ->where('status', OrderCouponSplitModel::STATUS_USED)
                                              ->when($couponIds, function ($query) use ($couponIds) {
                                                  $query->whereIn('couponId', $couponIds);
                                              })
                                              ->select(['couponDiscountPrice', 'couponCostPrice'])
                                              ->get();

        return [
            'name'  => $activityName,
            'count' => (int)$activityQuery->count(),
            'sum'   => (int)$activityQuery->sum('couponDiscountPrice') - (int)$activityQuery->sum('couponCostPrice'),
            // 券面值。如：花90买的100抵扣券，这里指100
        ];
    }

    /**
     * 将时间按照步长拆分成二维数组
     * @param $startAt int 开始时间
     * @param $endAt int 结束时间
     * @param $step int 步长
     */
    public function divisionTime(int $startAt, int $endAt, int $step): array
    {
        $divisionTime = [];
        for ($i = $startAt, $j = 1; $i < $endAt; $i += $step, $j++) {
            $divisionTime[$j]['startAt'] = $i;
            $divisionTime[$j]['endAt']   = $i + $step;
        }
        return $divisionTime;
    }

    /**
     * 查询分段订单实付金额
     * @param $shopId
     * @param $sourceType
     * @param $divisionTime
     * @return array
     */
    public function timeIntervalBusinessStatistics($shopId, $sourceType, $divisionTime)
    {
        //查询店铺基本信息
        $shopInfo         = ShopService::getShopInfo($shopId);
        $divisionTimeDate = [];
        foreach ($divisionTime as $k => $value) {
            //查询订单数据
            $payPrice = OrderSplitModel::suffix($shopId)->query()
                                       ->where(['shopId' => $shopId, 'orderStatus' => CodeEnum::ORDER_STATUS_FINISHED])
                                       ->whereIn('sourceType', $sourceType)
                                       ->whereBetween('createdAt', [$value['startAt'], $value['endAt']])
                                       ->sum('realPayPrice');

            $divisionTimeDate[$k - 1]['shopName'] = $shopInfo['name'];
            $divisionTimeDate[$k - 1]['startAt']  = date('Y-m-d H:i', $value['startAt']);
            $divisionTimeDate[$k - 1]['endAt']    = date('Y-m-d H:i', $value['endAt']);
            $divisionTimeDate[$k - 1]['payPrice'] = $payPrice;
        }
        return $divisionTimeDate;
    }


    /**
     * 店铺菜品销售统计
     * @param $typeName string 类型 1：菜品 2：分类 默认
     * @param $shopIds array  店铺id数组
     * @param $startAt int 开始时间
     * @param $endAt int 结束时间
     * @param $orderBy string  排序字段 num：销量 payPrice ： 实收 默认销量
     * @param $byType string 排序类型 正序 asc 倒叙 desc  默认倒叙
     * @return array
     */
    public function productSellStatistics(
        string $typeName,
        int $shopId,
        int $startAt,
        int $endAt,
        string $orderBy,
        string $byType
    ): array {
        $prefix           = config('other.DB_PREFIX', '');
        $orderName        = OrderTable::orderTableName($shopId);
        $orderDetailName  = OrderTable::orderDetailTableName($shopId);
        $payPrice         = 'SUM(' . $prefix . "$orderDetailName.payPrice)" . ' + ' . 'SUM(' . "{$prefix}" . "{$orderDetailName}.couponCostPrice)" . " as payPrice";
        $orderDetailTotal = DB::connection(OrderDb::orderDbConnection($shopId))->table("$orderName")
                              ->join("$orderDetailName", "$orderName.orderId", '=', "$orderDetailName.orderId")
                              ->select($typeName, DB::raw('SUM(num) as num'), 'productName', DB::raw("$payPrice"))
                              ->where('orderStatus', '=', CodeEnum::ORDER_STATUS_FINISHED)
                              ->where("$orderName.shopId", $shopId)
                              ->where("{$orderDetailName}.type", '=', ProductCodeEnum::PRODUCT_TYPE_SINGLE)
                              ->where("{$orderDetailName}.isDeleted", '=', 0)
                              ->where("{$orderDetailName}.refundNum", '=', 0)
                              ->whereBetween("$orderName.createdAt", [$startAt, $endAt])
                              ->groupBy($typeName)
                              ->orderBy($orderBy, $byType)
                              ->get()
                              ->toArray();
        return $this->doProductSellStatistics($typeName, $orderDetailTotal);
    }

    /**
     * 处理数据
     * @param $typeName
     * @param $orderDetailTotal
     * @return array
     */
    public function doProductSellStatistics($typeName, $orderDetailTotal): array
    {
        $item             = [];
        $totalNum         = 0;
        $totalPay         = 0;
        $categoryNameList = [];
        if ($typeName == CodeEnum::SELLING_STATISTICS_CODE_TEXT[CodeEnum::CATEGORY_SELLING_STATISTICS]) {
            //如果是分类，聚合分类id
            $categoryIds = array_column($orderDetailTotal, $typeName);
            //获取分类名称
            $cateList         = CategoryService::getCateListByIds($categoryIds);
            $categoryNameList = $cateList->keyBy('id')->toArray();
        }
        foreach ($orderDetailTotal as $v) {
            $totalNum += $v->num;
            $totalPay += $v->payPrice;
            if (!isset($item[$v->$typeName])) {
                $item[$v->$typeName]['num']         = $v->num;
                $item[$v->$typeName]['payPrice']    = $v->payPrice;
                $item[$v->$typeName]['productName'] = $v->productName;
                $item[$v->$typeName][$typeName]     = $v->$typeName;
                if ($categoryNameList) {
                    $item[$v->$typeName]['categoryName'] = !empty($v->$typeName) ? ($categoryNameList[$v->$typeName]['name'] ?? '暂无分类') : '暂无分类';
                }
            } else {
                $item[$v->$typeName]['num']      += $v->num;
                $item[$v->$typeName]['payPrice'] += $v->payPrice;
            }
        }
        foreach ($item as $key => $value) {
            $item[$key]['saleProportion'] = round($value['num'] / $totalNum * 100, 2) . ' %';
            $item[$key]['payProportion']  = round($value['payPrice'] / $totalPay * 100, 2) . ' %';
        }
        return ['totalNum' => $totalNum, 'totalPay' => $totalPay, 'list' => array_values($item)];
    }

    public function bProductSellStatistics($startAt, $endAt, $shopId, $orderBy, $byType, $source)
    {
        if ($source == CodeEnum::SOURCE_TYPE_SHOP) {
            return $this->bProductSellPosStatistics($startAt, $endAt, $shopId, $orderBy, $byType);
        } else {
            return $this->bProductSellWaiMaiStatistics($startAt, $endAt, $shopId, $orderBy, $byType);
        }
    }

    public function bProductSellWaiMaiStatistics($startAt, $endAt, $shopId, $orderBy, $byType)
    {
        $engine = (new SeparateService($startAt, $endAt))->check();
        if ($engine == SeparateService::DB) {
            $orderDetailName = WaiMaiOrderDetailModel::suffix($shopId)->getTable();
            $orderName       = WaiMaiOrderModel::suffix($shopId)->getTable();
            $prefix        = config('other.DB_PREFIX', '');

        } else {
            $orderDetailName = 'kf_waimai_order_details';
            $orderName = 'kf_waimai_orders';
            $prefix = '';
        }

        $payPrice      = 'SUM(' . $prefix . "$orderDetailName.incomes) as payPrice";//实收
        $originalPrice = 'SUM(' . $prefix . "$orderDetailName.originalPrice) as originalPrice";//原价
        $discountPrice = 'SUM(' . $prefix . "$orderDetailName.discountPrice) as discountPrice";//优惠价格

        if ($engine == SeparateService::DB) {
            $connection = DB::connection(OrderDb::orderDbConnection($shopId, OrderDb::DB_TYPE_WAIMAI))
                            ->table($orderName)
                            ->join($orderDetailName, "{$orderName}.orderId", '=',
                                "{$orderDetailName}.orderId")
                            ->select([
                                $orderName . '.sourceType',
                                'productName as productId',
                                'productName',
                                'unit',
                                DB::raw('SUM(num) as num'),
                                DB::raw("$payPrice"),
                                DB::raw("$originalPrice"),
                                DB::raw("$discountPrice")
                            ]);
        } else {

            $connection = WaiMaiOrderDetailCHModel::query()
                ->join($orderName, 'all', 'inner', ['orderId', 'orderId'])
                ->select([
                    'sourceType',
                    'productName as productId',
//                    raw('any(productName) as productName'),
                    raw('any(unit) as unit'),
                    raw('SUM(num) as num'),
                    raw("$payPrice"),
                    raw("$originalPrice"),
                    raw("$discountPrice")
                ]);
        }

        if ($orderBy == 'createdAt') {
            $orderBy = $orderName . '.' . $orderBy;
        }

        $waiMaiStatistics = $connection
                              ->where("{$orderName}.orderStatus", '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                              ->where("{$orderName}.shopId", '=', $shopId)
                              ->whereBetween("{$orderName}.createdAt", [$startAt, $endAt])
                              ->when($engine == SeparateService::DB, function ($q) use ($orderBy, $byType) {
                                  $q->orderBy($orderBy, $byType);
                              })
                              ->when($engine == SeparateService::CLICKHOUSE, function ($q) use ($orderBy, $byType) {
                                  $q->orderBy($orderBy, $byType);
                              })
                              ->groupBy('productId',  'sourceType')
                              ->get();

        if ($engine != SeparateService::DB) {
            $waiMaiStatistics = $waiMaiStatistics->map(function ($item) {
                $item['productName'] = $item['productId'];
                return $item;
            });
        }

        return $this->doBProductSellStatistics($waiMaiStatistics);
    }

    /**
     * 门店菜品统计
     * @param $startAt
     * @param $endAt
     * @param $shopId
     * @param $orderBy
     * @param $byType
     * @return array
     */
    public function bProductSellPosStatistics($startAt, $endAt, $shopId, $orderBy, $byType)
    {
        $engine = (new SeparateService($startAt, $endAt))->check();
        if ($engine == SeparateService::DB) {
            $prefix          = config('other.DB_PREFIX', '');
            $orderName       = OrderTable::orderTableName($shopId);
            $orderDetailName = OrderTable::orderDetailTableName($shopId);

        } else {
            $prefix          = '';
            $orderName       = 'kf_order';
            $orderDetailName = 'kf_order_detail';
        }

        $payPrice        = 'SUM(' . $prefix . "$orderDetailName.payPrice)" . ' + ' . 'SUM(' . "{$prefix}" . "{$orderDetailName}.couponCostPrice)" . " as payPrice";//实收 payPrice+couponCostPrice
        $originalPrice   = 'SUM(' . $prefix . "$orderDetailName.originalPrice) as originalPrice";//原价
        $discountPrice   = 'SUM(' . $prefix . "$orderDetailName.totalDiscountPrice)" . ' - ' . 'SUM(' . "{$prefix}" . "{$orderDetailName}.couponCostPrice)" . " as discountPrice";//优惠价格 totalDiscountPrice - couponCostPrice

        if ($engine == SeparateService::DB) {
            $model = DB::connection(OrderDb::orderDbConnection($shopId))
                       ->table("{$orderName}")
                       ->join("{$orderDetailName}", "{$orderName}.orderId", '=', "{$orderDetailName}.orderId")
                       ->select([
                           'sourceType',
                           'productId',
                           DB::raw('SUM(num) as num'),
                           DB::raw('SUM(refundNum) as refundNum'),
                           'productName',
                           'unit',
                           DB::raw("{$payPrice}"),
                           DB::raw("{$originalPrice}"),
                           DB::raw("{$discountPrice}")
                       ]);

        } else {
            $model = OrderDetailCHModel::query()
                ->join($orderName, 'all', 'inner', ['orderId', 'orderId'])
                ->select([
                    'sourceType',
                    'productId',
                    raw('SUM(num) as num'),
                    raw('SUM(refundNum) as refundNum'),
                    raw('any(productName) as productName'),
                    raw('any(unit) as unit'),
                    raw("{$payPrice}"),
                    raw("{$originalPrice}"),
                    raw("{$discountPrice}")
                ]);
        }

        if ($orderBy == 'createdAt') {
            $orderBy = $orderName . '.' . $orderBy;
        }

        $orderDetailTotal = $model
                              ->where('orderStatus', '=', CodeEnum::ORDER_STATUS_FINISHED)
                              ->where("{$orderName}.shopId", '=', $shopId)
                              ->where("{$orderDetailName}.isDeleted", '=', 0)
                              ->where("{$orderDetailName}.refundNum", '=', 0)
                              ->where("{$orderDetailName}.type", '=', ProductCodeEnum::PRODUCT_TYPE_SINGLE)
                              ->whereBetween("$orderName.completeTime", [$startAt, $endAt])
                                ->when($engine == SeparateService::DB, function ($q) use ($orderBy, $byType) {
                                    $q->orderBy($orderBy, $byType);
                                })
                                ->when($engine == SeparateService::CLICKHOUSE, function ($q) use ($orderBy, $byType) {
                                    $q->orderBy($orderBy, $byType);
                                })
                              ->orderBy('productId', $byType)
                              ->groupBy('productId', 'sourceType')
                              ->get();

        return $this->doBProductSellStatistics($orderDetailTotal);
    }


    /**
     * b端数据处理
     * @param $orderDetailTotal
     * @return array
     */
    public function doBProductSellStatistics($orderDetailTotal): array
    {
        $totalNum           = 0;
        $totalPay           = 0;
        $totalDiscount      = 0;
        $totalOriginalPrice = 0;
        $item               = [];
        foreach ($orderDetailTotal as $v) {
            if (isset($v->refundNum)) {
                $totalNum += $v->num - $v->refundNum;
            } else {
                $totalNum += $v->num;
            }
            $totalPay           += $v->payPrice;
            $totalDiscount      += $v->discountPrice;
            $totalOriginalPrice += $v->originalPrice;
        }
        foreach ($orderDetailTotal as $key => $value) {
            $item[$key]['id']          = $key;
            $item[$key]['productName'] = $value->productName;
            $item[$key]['unit']        = $value->unit;
            $item[$key]['sourceType']  = CodeEnum::SOURCE_TYPES[$value->sourceType];
            if (isset($value->refundNum)) {
                $item[$key]['num'] = $value->num - $value->refundNum;
            } else {
                $item[$key]['num'] = $value->num;
            }

            $item[$key]['saleProportion']          = round(($value->num) / $totalNum * 100,
                    2) . ' %';
            $item[$key]['originalPrice']           = $value->originalPrice;
            $item[$key]['originalPriceProportion'] = $totalOriginalPrice == 0 ? "0 %" : round($value->originalPrice / $totalOriginalPrice * 100,
                    2) . ' %';
            $item[$key]['payPrice']                = $value->payPrice;
            $item[$key]['payProportion']           = $totalPay == 0 ? "0 %" : round($value->payPrice / $totalPay * 100,
                    2) . ' %';
            $item[$key]['discount']                = $value->discountPrice;
            $item[$key]['discountProportion']      = $totalDiscount == 0 ? "0 % " : round($value->discountPrice / $totalDiscount * 100,
                    2) . ' %';
        }
        return [
            'totalNum'           => $totalNum,
            'totalPay'           => round($totalPay, 2),
            'totalDiscountPrice' => round($totalDiscount, 2),
            'totalOriginalPrice' => round($totalOriginalPrice, 2),
            'list'               => array_values($item)
        ];
    }

    /**
     * 导出数据/100
     * @param $data
     * @param $integer
     * @return array
     */
    public static function divideInteger($data, $integer): array
    {
        $newData['totalNum']           = $data['totalDiscountPrice'];
        $newData['totalPay']           = $data['totalPay'] / $integer;
        $newData['totalDiscountPrice'] = $data['totalDiscountPrice'] / $integer;
        $newData['totalOriginalPrice'] = $data['totalOriginalPrice'] / $integer;
        $newData['list']               = [];
        foreach ($data['list'] as $key => $value) {
            $newData['list'][$key]['productName']             = $value['productName'];
            $newData['list'][$key]['unit']                    = $value['unit'];
            $newData['list'][$key]['sourceType']              = $value['sourceType'];
            $newData['list'][$key]['num']                     = $value['num'];
            $newData['list'][$key]['saleProportion']          = $value['saleProportion'];
            $newData['list'][$key]['originalPrice']           = $value['originalPrice'] / $integer;
            $newData['list'][$key]['originalPriceProportion'] = $value['originalPriceProportion'];
            $newData['list'][$key]['payPrice']                = $value['payPrice'] / $integer;
            $newData['list'][$key]['payProportion']           = $value['payProportion'];
            $newData['list'][$key]['discount']                = $value['discount'] / $integer;
            $newData['list'][$key]['discountProportion']      = $value['discountProportion'];
        }
        return $newData;
    }

    /**
     * 获取订单关联信息
     * @param $shopId
     * @param $payChannel
     * @param $sourceType
     * @param $completeTimeStart
     * @param $completeTimeEnd
     * @return array|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Traits\Conditionable[]
     */
    public static function getOrderMappingData(
        $shopId,
        $payChannel,
        $sourceType,
        $completeTimeStart,
        $completeTimeEnd,
        bool $returnLists = true
    ) {
        if (Util::isDate($completeTimeStart)) {
            $completeTimeStart .= ' 00:00:00';
        }
        if (Util::isDate($completeTimeEnd)) {
            $completeTimeEnd .= ' 23:59:59';
        }
        $sourceType = $sourceType > 0 ? [$sourceType] : [];
        return OrderSplitModel::getOrderDiscountList($shopId, $payChannel, $sourceType, $completeTimeStart,
                                  $completeTimeEnd, $returnLists);
    }

    /**
     * 店内订单导出信息组装
     * @param $storeOrderList
     * @param $shopInfo
     * @return array
     */
    public static function getInStoreOrderToChange(
        $storeOrderList,
        $shopInfo
    ): array {
        $rows = self::yieldOrderInfo($storeOrderList, $shopInfo);

        return [
            'title' => '订单明细',
            'info'  => [
                '门店'     => $shopInfo['name'],
                '门店编码' => str_pad($shopInfo['shopCode'],
                    ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT),//门店编号
            ],
            'rows'  => $rows
        ];
    }

    public static function yieldOrderInfo($storeOrderList, $shopInfo)
    {
        $rows = [
            '门店编号',
            '门店',
            '订单编号',
            '订单来源',
            '用餐方式',
            '营业日期',
            '下单时间',
            '流水号',
            '营业额',
            '优惠金额',
            '营业收入',
            '结算金额',
            '佣金',
            '订单状态',
            '敏感操作（次）',
            '会员',
            '整单备注'
        ];
        yield $rows;
        foreach ($storeOrderList as $key => $value) {
            $sensitive = 0;
            //试吃
            if ($value['payChannel'] == CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                $sensitive += 1;
            }
            //赠菜 和菜品打折
            foreach ($value['orderDetailRel'] as $detail) {
                if ($detail['freeNum'] > 0) {
                    $sensitive += 1;
                }
                if ($detail['discountPrice'] > 0) {
                    $sensitive += 1;
                }
            }
            if (!empty($value['orderDiscountRel'])) {
                $sensitive += count($value['orderDiscountRel']);
            }
            $rows[$key + 1] =
                [
                    str_pad($shopInfo['shopCode'], ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0",
                        STR_PAD_LEFT),
                    $shopInfo['name'],
                    $value['orderId'] . ' ',
                    CodeEnum::SOURCE_TYPES[$value['sourceType']],
                    '堂食',
                    date("Y-m-d", strtotime($value['createdAt'])),
                    date("Y-m-d H:i:s", strtotime($value['createdAt'])),
                    str_pad($value['serialNum'], CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
                    $value['originalPrice'] / 100,
                    $value['realDiscountPrice'] / 100,
                    $value['realPayPrice'] / 100,
                    ($value['realPayPrice'] - $value['brokerage']) / 100,
                    $value['brokerage'] / 100,
                    CodeEnum::STATUS_CODE_TEXT[$value['orderStatus']],
                    $sensitive,
                    '否',
                    $value['remark']
                ];
            yield $rows[$key + 1];
        }
    }


    public static function getInStoreProductToChange(
        $storeOrderList,
        $shopInfo
    ) {
        $rows = self::yieldInStoreProduct($storeOrderList, $shopInfo);
        return [
            'title' => '菜品明细',
            'info'  => [
                '门店'     => $shopInfo['name'],
                '门店编码' => str_pad($shopInfo['shopCode'],
                    ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT),//门店编号
            ],
            'rows'  => $rows
        ];
    }

    public static function yieldInStoreProduct($storeOrderList, $shopInfo)
    {
        $rows = [
            '门店编号',
            '门店',
            '订单编号',
            '流水号',
            '菜品编码',
            '菜品名称',
            '是否退菜',
            '单位',
            "销售数量",
            "菜品单价",
            "营业额",
            "菜品优惠",
            "菜品收入",
        ];
        yield $rows;
        $key = 0;
        foreach ($storeOrderList as $v) {
            foreach ($v['orderDetailRel'] as $value) {
                $refund = '否';
                if ($value->refundNum > 0) {
                    $refund = '是';
                }
                $rows[$key + 1] = [
                    str_pad($shopInfo['shopCode'], ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO],
                        "0", STR_PAD_LEFT),
                    $shopInfo['name'],
                    $value->orderId . ' ',
                    str_pad($v->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0",
                        STR_PAD_LEFT),
                    $value->productId,
                    $value->productName,
                    $refund,
                    $value->unit,
                    $value->num - $value->refundNum,
                    $value->originalUnitPrice / 100,
                    $value->originalPrice / 100,
                    ($value->totalDiscountPrice - $value->couponCostPrice) / 100,
                    ($value->payPrice + $value->couponCostPrice) / 100,
                ];
                yield $rows[$key + 1];
                $key += 1;
            }
        }

//        return $rows;
    }

    public static function getInStorePayStream(
        $storeOrderList,
        $shopInfo,
        $isGetOther = false
    ): array {
        $orderIds       = $storeOrderList->pluck('orderId')->toArray();
        $payStream      = self::getPayStream($orderIds);
        $payDataKeyBy   = $payStream['pay'];
        $refundData     = $payStream['refund'];
        $i              = 0;
        $rows           = [];
        foreach ($storeOrderList as $key => $item) {
            //处理第三方支付以及现金
            if (isset($payDataKeyBy[$item['orderId']])) {
                $isReduce = false;
                foreach ($payDataKeyBy[$item['orderId']] as $payItem) {
                    if ($payItem['isPaidIn'] == PayStreamModel::PAID_IN_YES || $isGetOther) {
                        $rows[$i][] = str_pad($shopInfo['shopCode'],
                            ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                        $rows[$i][] = $shopInfo['name'];
                        $rows[$i][] = $item['orderId'] . ' ';

                        // 支付-Start
                        switch ($payItem['payChannel']) {
                            case CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK:
                                $rows[$i][] = '试吃';
                                $payType    = CodeEnum::ORDER_INFO_PAY_TYPE_TOTAL;
                                break;
                            case CodeEnum::ORDER_PAY_CHANNEL_MA_LING:
                                $rows[$i][] = '抹零';
                                $payType    = CodeEnum::ORDER_INFO_PAY_TYPE_TOTAL;
                                break;
                            case $payItem['payChannel'] > CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK:
                                $rows[$i][] = "自定义支付：" . (string)optional($payItem->streamCustomPaymentRel)->name;
                                $payType    = CodeEnum::ORDER_INFO_PAY_TYPE_REAL;
                                break;
                            case PayStreamModel::PAY_CHANNEL_FY:
                                $rows[$i][] = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$payItem['payChannelChild']] ?? '';
                                $payType    = CodeEnum::ORDER_INFO_PAY_TYPE_REAL;
                                break;
                            default:
                                $rows[$i][] = CodeEnum::CHANNEL_CODE_TEXT[$payItem['payChannel']];
                                $payType    = CodeEnum::ORDER_INFO_PAY_TYPE_REAL;
                        }
                        // 支付-End

                        $rows[$i][] = 0;
                        //减去券包金额 如果小于自定义支付 代表是第三方正常支付 并且还没有减过券包金额
                        if (!empty($item['order_ext_one_rel']) && !$isReduce && $payItem['payChannel'] < CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                            $rows[$i][] = ($payItem['payPrice'] - (int)optional($item->orderExtOneRel)->payPrice) / 100;
                            $isReduce   = true;
                        } else {
                            $rows[$i][] = $payItem['payPrice'] / 100;
                        }
                        $rows[$i][] = date("Y-m-d H:i:s", $payItem['paySuccessTime']);
                        $rows[$i][] = CodeEnum::ORDER_PAY_STATUSES[$payItem['payStatus']];
                        if ($payItem->streamShopRel) {
                            $payConfig  = json_decode((string)optional($payItem->streamShopRel)->payConfig, 'true');
                            $rows[$i][] = $payConfig['mch_id'];
                        } else {
                            $rows[$i][] = '--';
                        }
                        $rows[$i][] = $payItem['thirdPayNo'];
                        $rows[$i][] = CodeEnum::REFUND_CODE_TEXT[$item['refundStatus']];
                        if (isset($refundData[$payItem['payNo']])) {
                            $rows[$i][] = $refundData[$payItem['payNo']]['refundTotalPrice'] / 100;
                        } else {
                            $rows[$i][] = '--';
                        }
                        $rows[$i][] = $item['updatedBy'];
                        if ($isGetOther) {
                            $rows[$i][] = $payItem['payChannel'];
                            $rows[$i][] = $payItem['isPaidIn'];
                            $rows[$i][] = $payType;
                            $rows[$i][] = $rows[$i][5];
                        }
                        $i++;
                    }
                }
            }
            //用户优惠券成本大于0的
            if ($item->orderCouponRel->count()) {
                foreach ($item->orderCouponRel as $coupon) {
                    if ($coupon['couponCostPrice'] > 0) {
                        $rows[$i][] = str_pad($shopInfo['shopCode'],
                            ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                        $rows[$i][] = $shopInfo['name'];
                        $rows[$i][] = $coupon['orderId'] . ' ';
                        $rows[$i][] = $coupon['couponName'];
                        $rows[$i][] = ($coupon['couponDiscountPrice'] - $coupon['couponCostPrice']) / 100;
                        $rows[$i][] = $coupon['couponCostPrice'] / 100;
                        $rows[$i][] = date("Y-m-d H:i:s", $coupon['createdAt']);
                        $rows[$i][] = CodeEnum::ORDER_PAY_STATUSES[$item['payStatus']];
                        $rows[$i][] = '--';
                        $rows[$i][] = '--';
                        $rows[$i][] = CodeEnum::REFUND_CODE_TEXT[$item['refundStatus']];
                        $rows[$i][] = '--';
                        $rows[$i][] = $item['updatedBy'];
                        if ($isGetOther) {
                            $rows[$i][] = 0;
                            $rows[$i][] = 1;
                            $rows[$i][] = CodeEnum::ORDER_INFO_PAY_TYPE_REAL;
                            $rows[$i][] = $coupon['couponType'] == 3 ? 0 : $coupon['couponNum'] / 100; //售价
                        }
                        $i++;
                    }
                }
            }
            //第三方优惠券成本大于0
            if ($item->orderCouponExtRel->count()) {
                foreach ($item->orderCouponExtRel as $ext) {
                    if ($ext['couponExtCostPrice'] > 0) {
                        $rows[$i][] = str_pad($shopInfo['shopCode'],
                            ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                        $rows[$i][] = $shopInfo['name'];
                        $rows[$i][] = $ext['orderId'] . ' ';
                        $rows[$i][] = $ext['couponExtName'];
                        $rows[$i][] = ($ext['couponExtDiscountPrice'] - $ext['couponExtCostPrice']) / 100;
                        $rows[$i][] = $ext['couponExtCostPrice'] / 100;
                        $rows[$i][] = $ext['createdAt'];
                        $rows[$i][] = CodeEnum::ORDER_PAY_STATUSES[$item['payStatus']];
                        $rows[$i][] = '--';
                        $rows[$i][] = '--';
                        $rows[$i][] = CodeEnum::REFUND_CODE_TEXT[$item['refundStatus']];
                        $rows[$i][] = '--';
                        $rows[$i][] = $item['updatedBy'];
                        if ($isGetOther) {
                            $rows[$i][] = 0;
                            $rows[$i][] = 1;
                            $rows[$i][] = CodeEnum::ORDER_INFO_PAY_TYPE_REAL;
                            $rows[$i][] = $ext['couponExtDiscountPrice'] / 100;
                        }
                        $i++;
                    }
                }
            }

        }
        return $rows;
    }

    public static function getInStoreDiscountData(
        $storeOrderList,
        $shopInfo,
        $isGetOther = false
    ): array {
        $orderIds     = $storeOrderList->pluck('orderId')->toArray();
        $payStream    = self::getPayStream($orderIds);
        $payDataKeyBy = $payStream['pay'];
        $refundData   = $payStream['refund'];
        $i            = 0;
        $rows         = [];
        foreach ($storeOrderList as $item) {
            //处理第三方支付以及现金
            if (isset($payDataKeyBy[$item['orderId']])) {
                foreach ($payDataKeyBy[$item['orderId']] as $payItem) {
                    if ($payItem['isPaidIn'] == PayStreamModel::PAID_IN_NO) {
                        if (isset($refundData[$payItem['payNo']])) {
                            $payPrice = ($payItem['payPrice'] - $refundData[$payItem['payNo']]['refundTotalPrice']) / 100;
                        } else {
                            $payPrice = $payItem['payPrice'] / 100;
                        }
                        if ($payPrice > 0) {
                            $rows[$i][] = str_pad($shopInfo['shopCode'],
                                ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                            $rows[$i][] = $shopInfo['name'];
                            $rows[$i][] = $item['orderId'] . ' ';

                            // 支付-Start
                            switch ($payItem['payChannel']) {
                                case CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK:
                                    $name     = '试吃';
                                    $nameDesc = $payPrice . '元';
                                    break;
                                case CodeEnum::ORDER_PAY_CHANNEL_MA_LING:
                                    $name     = '抹零';
                                    $nameDesc = $payPrice . '元';
                                    break;
                                case $payItem['payChannel'] > CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK:
                                    $name     = "自定义支付";
                                    $nameDesc = $payItem['streamCustomPaymentRel']['name'];
                                    break;
                                default:
                                    $name     = CodeEnum::CHANNEL_CODE_TEXT[$payItem['payChannel']];
                                    $nameDesc = $payPrice . '元';
                            }
                            // 支付-End

                            $rows[$i][] = $name;
                            $rows[$i][] = $name . ':' . $nameDesc;
                            $rows[$i][] = "--";
                            $rows[$i][] = $payPrice;
                            if ($isGetOther) {
                                $rows[$i][] = $payItem['isPaidIn'];
                                $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_PAY;
                            }
                            $i++;
                        }
                    }
                }
            }
            if (!empty($item['orderCouponRel'])) {
                foreach ($item['orderCouponRel'] as $coupon) {
                    $rows[$i][] = str_pad($shopInfo['shopCode'],
                        ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                    $rows[$i][] = $shopInfo['name'];
                    $rows[$i][] = $coupon['orderId'] . ' ';
                    if ($coupon['couponType'] == CouponEnum::COUPON_TYPE_DISCOUNT) {
                        $discountType = '优惠券-折扣券：';
                    } elseif ($coupon['couponType'] == CouponEnum::COUPON_TYPE_EXCHANGE) {
                        $discountType = '优惠券-商品兑换券：';
                    } else {
                        $discountType = '优惠券-代金券：';
                    }
                    $rows[$i][] = '优惠券';
                    $rows[$i][] = $discountType . $coupon['couponName'];
                    $rows[$i][] = '--';
                    $rows[$i][] = ($coupon['couponDiscountPrice'] - $coupon['couponCostPrice']) / 100;
                    if ($isGetOther) {
                        $rows[$i][] = 0;
                        $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_PAY;
                    }
                    $i++;
                }
            }
            if (!empty($item['orderCouponExtRel'])) {
                foreach ($item['orderCouponExtRel'] as $ext) {
                    $platformName   = CouponExtEnum::EXT_PLATFORM_TEXT[$ext['extPlatform']];
                    $couponTypeName = CouponExtEnum::COUPON_TYPE_TEXT[$ext['couponExtType']];
                    $rows[$i][]     = str_pad($shopInfo['shopCode'],
                        ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                    $rows[$i][]     = $shopInfo['name'];
                    $rows[$i][]     = $ext['orderId'] . ' ';
                    $rows[$i][]     = $platformName . $couponTypeName;
                    $rows[$i][]     = $platformName . $couponTypeName . ":" . $ext['couponExtName'];
                    $rows[$i][]     = '--';
                    $rows[$i][]     = ($ext['couponExtDiscountPrice'] - $ext['couponExtCostPrice']) / 100;
                    if ($isGetOther) {
                        $rows[$i][] = 0;
                        $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_PAY;
                    }
                    $i++;
                }
            }
            if (!empty($item['orderDiscountRel'])) {
                foreach ($item['orderDiscountRel'] as $discount) {
                    $rows[$i][] = str_pad($shopInfo['shopCode'],
                        ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                    $rows[$i][] = $shopInfo['name'];
                    $rows[$i][] = $discount['orderId'] . ' ';
                    $rows[$i][] = '手动优惠';
                    if ($discount['discountType'] == CodeEnum::PRODUCTION_DISCOUNT_TYPE_COUNT) {
                        $rows[$i][] = '整单打折：' . $discount['discountNum'] / 10 . '折';
                    } else {
                        $rows[$i][] = '整单减免：' . $discount['discountNum'] / 100 . '元';
                    }
                    $rows[$i][] = '--';
                    $rows[$i][] = $discount['discountPrice'] / 100;
                    if ($isGetOther) {
                        $rows[$i][] = 0;
                        $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_ORDER;
                        $rows[$i][] = 0;
                    }
                    $i++;
                }
            }
            foreach ($item['orderDetailRel'] as $detail) {
                if ($detail['discountNum'] > 0) {
                    $rows[$i][] = str_pad($shopInfo['shopCode'],
                        ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                    $rows[$i][] = $shopInfo['name'];
                    $rows[$i][] = $detail['orderId'] . ' ';
                    $rows[$i][] = '手动优惠';
                    if ($detail['discountType'] == 1) {
                        $rows[$i][] = "菜品优惠" . '-折扣：' . $detail['discountNum'] / 10 . '折';
                    } else {
                        $rows[$i][] = "菜品优惠" . '-减免：' . $detail['discountNum'] / 100 . '元';
                    }
                    $rows[$i][] = '--';
                    $rows[$i][] = $detail['discountPrice'] / 100;
                    if ($isGetOther) {
                        $rows[$i][] = 0;
                        $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_ORDER;
                        $rows[$i][] = 0;
                    }
                    $i++;
                }
                if ($detail['freeNum']) {
                    $rows[$i][] = str_pad($shopInfo['shopCode'],
                        ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
                    $rows[$i][] = $shopInfo['name'];
                    $rows[$i][] = $detail['orderId'] . ' ';
                    $rows[$i][] = '手动优惠';
                    $rows[$i][] .= '赠菜：' . $detail['productName'];
                    $rows[$i][] = '--';
                    $rows[$i][] = $detail['originalPrice'] / 100;
                    if ($isGetOther) {
                        $rows[$i][] = 0;
                        $rows[$i][] = CodeEnum::ORDER_INFO_COUPON_TYPE_ORDER;
                        $rows[$i][] = $detail['packageDetailId'];
                    }
                    $i++;
                }
            }
        }
        return $rows;
    }

    public static function getPayStream($orderIds)
    {
        //按照200分组
        $chunk      = array_chunk($orderIds, 200);
        $payData    = collect();
        $refundData = [];
        foreach ($chunk as $value) {
            $arr     = PayStreamModel::getPayStreamListByIds($value);
            $payData = $arr->concat($payData);

            //查询退款流水
            $refundField = [DB::raw("sum(refundPrice) as refundTotalPrice"), 'payNo'];
            $payNos      = $arr->pluck('payNo')->toArray();
            $refundArr   = RefundStreamModel::getRefundStreamByPayNos($payNos, $refundField);
            $refundData  = array_merge($refundData, $refundArr);
        }
        $payDataKeyBy = [];
        foreach ($payData as $datum) {
            if (isset($payDataKeyBy[$datum['orderId']]['payChannel']) && $payDataKeyBy[$datum['orderId']]['payChannel'] == $datum['payChannel']) {
                $datum['payPrice'] = $datum['payPrice'] + $payDataKeyBy[$datum['orderId']]['payPrice'];
            }
            $payDataKeyBy[$datum['orderId']][] = $datum;
        }
        $refundData = array_column($refundData, null, 'payNo');
        return ['pay' => $payDataKeyBy, 'refund' => $refundData];
    }
}
